// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

#include <android/asset_manager_jni.h>
#include <android/native_window_jni.h>
#include <android/native_window.h>

#include <android/log.h>

#include <jni.h>

#include <string>
#include <vector>

#include <platform.h>
#include <benchmark.h>

#include "yolo.h"

#include "ndkcamera.h"

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/imgcodecs/imgcodecs.hpp>

#include <fstream>

#if __ARM_NEON
#include <arm_neon.h>
#endif // __ARM_NEON

// 新增的全局变量和锁
static cv::Mat processedMat;             // 用于保存处理后的图像
static ncnn::Mutex matLock;              // 保护 processedMat 的访问同步

static std::string globalSavePath;

#include <fstream>
#include <iomanip> // 添加头文件

// 保存结果到Excel的辅助函数
void saveToExcel(const std::string& imageName, const std::vector<Object>& objects,
                 const std::vector<std::string>& groundTruths)
{
    std::unordered_map<int, std::string> labelMap = {
            {0, "side_import_left_main_right_side"},
            {1, "main_export_left_main_right_side"},
            {2, "main_import_left_main_right_side"},
            {3, "main_import_left_side_right_main"},
            {4, "main_export_left_side_right_main"},
            {5, "side_export_left_side_right_main"},
            {6, "side_export_left_main_right_side"},
            {7, "side_import_left_side_right_main"},



    };
    // 写入原始数据到 Sheet1
    int row = 0;
    int col = 0;

    int totalObjects = objects.size();
    int totalGroundTruths = groundTruths.size();
    int missPredictions = 0;
    int incorrectPredictions = 0;
    int falsealarmPredictions = 0;

    if (globalSavePath.empty()) {
        __android_log_print(ANDROID_LOG_WARN, "ncnn", "保存路径未设置，跳过Excel保存");
        return;
    }

    std::string excelPath = globalSavePath + "/results.xlsx";
    static bool firstWrite = true;

    std::ofstream excelFile;
    if (firstWrite) {
        excelFile.open(excelPath, std::ios::out);
        excelFile << "图片名称\t实际类别\t预测类别\t置信度\t位置(x,y)\t尺寸(宽,高)\n";
        firstWrite = false;
    } else {
        excelFile.open(excelPath, std::ios::app);
    }

        if (excelFile.is_open()) {
            // 分别处理 groundTruths 和 objects
            size_t truthSize = groundTruths.size();
            size_t objectSize = objects.size();

            // 如果 objects 和 groundTruths 都为空，仍然写入一行数据
            if (objectSize == 0 && truthSize == 0) {
                excelFile << imageName << "\t" << "-" << "\t" << "-" << "\t" << "-" << "\t" << "-"
                          << "\t" << "-\n";
            }else{
                for (size_t i = 0; i < std::max(truthSize, objectSize); ++i) {
                    const auto *obj = (i < objectSize) ? &objects[i] : nullptr;
                    const auto *truth = (i < truthSize) ? &groundTruths[i] : nullptr;

                    // 更新统计变量
                    totalObjects += objects.size();
                    totalGroundTruths += groundTruths.size();

                    std::string truthLabelStr = (truth != nullptr) ? *truth : "";
                    int truthLabel = -1;
                    if (!truthLabelStr.empty()) {
                        std::istringstream truthStream(truthLabelStr);
                        truthStream >> truthLabel;
                    }

                    // 统计正确和错误的预测
                    if (obj != nullptr && truth != nullptr && obj->label != truthLabel) {
                        incorrectPredictions++;
                    } else if (obj == nullptr && truth != nullptr) {
                        missPredictions++;
                    } else if (obj != nullptr && truth == nullptr) {
                        falsealarmPredictions++;
                    }

                    std::string probStr = "-";
                    if (obj != nullptr) {
                        std::ostringstream oss;
                        oss << std::fixed << std::setprecision(2) << obj->prob;
                        probStr = oss.str();
                    }


                    std::string truthLabelDesc = (truthLabel != -1 ) ? labelMap[truthLabel] : "-";

                    std::string objLabelDesc = (obj != nullptr ) ? labelMap[obj->label] : "-";

                    excelFile << imageName << "\t"
//                              << truthLabel << "\t"
//                              << (truthLabel != -1 ? std::to_string(truthLabel):  "-" ) << "\t"
//                              << (obj != nullptr ? std::to_string(obj->label) : "-") << "\t"
                                << truthLabelDesc << "\t"
                                << objLabelDesc << "\t"
                                << (obj != nullptr ? "(" + std::to_string(obj->rect.x) + "," +
                                                   std::to_string(obj->rect.y) + ")" : "-") << "\t"
                                 << (obj != nullptr ? "(" + std::to_string(obj->rect.width) + "," +
                                                   std::to_string(obj->rect.height) + ")" : "-")
                                << "\n";



                }
            }

            excelFile.close();
        __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "结果已保存到Excel: %s", excelPath.c_str());
    } else {
        __android_log_print(ANDROID_LOG_ERROR, "ncnn", "Excel文件: %s", excelPath.c_str());
    }


//    // 新增：将统计信息写入txt文件
//    std::string staticsfile = globalSavePath + "/statics.txt";
//
//    std::ofstream txtFile(staticsfile, std::ios::app);
//    if (txtFile.is_open()) {
//        txtFile << "图片名称: " << imageName << "\n";
//        txtFile << "统计结果:\n";
//        txtFile << "总对象数: " << totalObjects << "\n";
//        txtFile << "总真实标签数: " << totalGroundTruths << "\n";
//        txtFile << "错误预测数: " << incorrectPredictions << "\n";
//        txtFile << "漏检数: " << missPredictions << "\n";
//        txtFile << "过检数: " << falsealarmPredictions << "\n";
//        txtFile << "------------------------\n"; // 分隔线，便于查看多个图片的统计
//
//        txtFile.close();
//        __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "统计信息已保存到txt: %s", staticsfile.c_str());
//    } else {
//        __android_log_print(ANDROID_LOG_ERROR, "ncnn", "无法创建txt文件: %s", staticsfile.c_str());
//    }


}

// 从标签文件读取真实类别
std::vector<std::string> readGroundTruth(const std::string& imageName, AAssetManager* assetManager)
{
    std::vector<std::string> truths;
    std::string labelPath = "val/labels/" + imageName + ".txt";

    // 使用AAssetManager读取标签文件
    AAsset* asset = AAssetManager_open(assetManager, labelPath.c_str(), AASSET_MODE_BUFFER);
    if (asset) {
        size_t size = AAsset_getLength(asset);
        char* buffer = new char[size + 1];
        AAsset_read(asset, buffer, size);
        buffer[size] = '\0';

        std::istringstream iss(buffer);
        std::string line;
        while (std::getline(iss, line)) {
            truths.push_back(line);
        }

        delete[] buffer;
        AAsset_close(asset);
    }

    return truths;
}



static int draw_unsupported(cv::Mat& rgb)
{
    const char text[] = "unsupported";

    int baseLine = 0;
    cv::Size label_size = cv::getTextSize(text, cv::FONT_HERSHEY_SIMPLEX, 1.0, 1, &baseLine);

    int y = (rgb.rows - label_size.height) / 2;
    int x = (rgb.cols - label_size.width) / 2;

    cv::rectangle(rgb, cv::Rect(cv::Point(x, y), cv::Size(label_size.width, label_size.height + baseLine)),
                    cv::Scalar(255, 255, 255), -1);

    cv::putText(rgb, text, cv::Point(x, y + label_size.height),
                cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(0, 0, 0));

    return 0;
}

static int draw_fps(cv::Mat& rgb)
{
    // resolve moving average
    float avg_fps = 0.f;
    {
        static double t0 = 0.f;
        static float fps_history[10] = {0.f};

        double t1 = ncnn::get_current_time();
        if (t0 == 0.f)
        {
            t0 = t1;
            return 0;
        }

        float fps = 1000.f / (t1 - t0);
        t0 = t1;

        for (int i = 9; i >= 1; i--)
        {
            fps_history[i] = fps_history[i - 1];
        }
        fps_history[0] = fps;

        if (fps_history[9] == 0.f)
        {
            return 0;
        }

        for (int i = 0; i < 10; i++)
        {
            avg_fps += fps_history[i];
        }
        avg_fps /= 10.f;
    }

    char text[32];
    sprintf(text, "FPS=%.2f", avg_fps);

    int baseLine = 0;
    cv::Size label_size = cv::getTextSize(text, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);

    int y = 0;
    int x = rgb.cols - label_size.width;

    cv::rectangle(rgb, cv::Rect(cv::Point(x, y), cv::Size(label_size.width, label_size.height + baseLine)),
                    cv::Scalar(255, 255, 255), -1);

    cv::putText(rgb, text, cv::Point(x, y + label_size.height),
                cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0));

    return 0;
}

static Yolo* g_yolo = 0;
static ncnn::Mutex lock;

class MyNdkCamera : public NdkCameraWindow
{
public:
    virtual void on_image_render(cv::Mat& rgb) const;
};

void MyNdkCamera::on_image_render(cv::Mat& rgb) const
{

//    __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "##########摄像头里不进行检测图片，使用文件夹的图片#############");
//    {
//        ncnn::MutexLockGuard g(lock);
//
//        if (g_yolo)
//        {
//            std::vector<Object> objects;
//            g_yolo->detect(rgb, objects);
//
//            g_yolo->draw(rgb, objects);
//        }
//        else
//        {
//            draw_unsupported(rgb);
//        }
//    }
//
//    draw_fps(rgb);
}

static MyNdkCamera* g_camera = 0;

extern "C" {

JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "JNI_OnLoad");

    g_camera = new MyNdkCamera;

    return JNI_VERSION_1_4;
}

JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved)
{
    __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "JNI_OnUnload");

    {
        ncnn::MutexLockGuard g(lock);

        delete g_yolo;
        g_yolo = 0;
    }

    delete g_camera;
    g_camera = 0;
}

// public native boolean loadModel(AssetManager mgr, int modelid, int cpugpu);
JNIEXPORT jboolean JNICALL Java_com_tencent_yolov8ncnn_Yolov8Ncnn_loadModel(JNIEnv* env, jobject thiz, jobject assetManager, jint modelid, jint cpugpu)
{
    if (modelid < 0 || modelid > 6 || cpugpu < 0 || cpugpu > 1)
    {
        return JNI_FALSE;
    }

    AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);

    __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "loadModel %p", mgr);

    const char* modeltypes[] =
    {
        "n",
        "s",
    };

    const int target_sizes[] =
    {
        640,
        640,
    };

    const float mean_vals[][3] =
    {
        {103.53f, 116.28f, 123.675f},
        {103.53f, 116.28f, 123.675f},
    };

    const float norm_vals[][3] =
    {
        { 1 / 255.f, 1 / 255.f, 1 / 255.f },
        { 1 / 255.f, 1 / 255.f, 1 / 255.f },
    };

    const char* modeltype = modeltypes[(int)modelid];
    int target_size = target_sizes[(int)modelid];
    bool use_gpu = (int)cpugpu == 1;

    // reload
    {
        ncnn::MutexLockGuard g(lock);

        if (use_gpu && ncnn::get_gpu_count() == 0)
        {
            // no gpu
            delete g_yolo;
            g_yolo = 0;
        }
        else
        {
            if (!g_yolo)
                g_yolo = new Yolo;
            g_yolo->load(mgr, modeltype, target_size, mean_vals[(int)modelid], norm_vals[(int)modelid], use_gpu);
        }
    }

    return JNI_TRUE;
}

// public native boolean openCamera(int facing);
JNIEXPORT jboolean JNICALL Java_com_tencent_yolov8ncnn_Yolov8Ncnn_openCamera(JNIEnv* env, jobject thiz, jint facing)
{
    if (facing < 0 || facing > 1)
        return JNI_FALSE;

    __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "openCamera %d", facing);

    g_camera->open((int)facing);

    return JNI_TRUE;
}

// public native boolean closeCamera();
JNIEXPORT jboolean JNICALL Java_com_tencent_yolov8ncnn_Yolov8Ncnn_closeCamera(JNIEnv* env, jobject thiz)
{
    __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "closeCamera");

    g_camera->close();

    return JNI_TRUE;
}

// public native boolean setOutputWindow(Surface surface);
JNIEXPORT jboolean JNICALL Java_com_tencent_yolov8ncnn_Yolov8Ncnn_setOutputWindow(JNIEnv* env, jobject thiz, jobject surface)
{
    ANativeWindow* win = ANativeWindow_fromSurface(env, surface);

    __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "setOutputWindow %p", win);

    g_camera->set_window(win);

    return JNI_TRUE;
}

// 新增图片处理方法  原始
//JNIEXPORT jboolean JNICALL Java_com_tencent_yolov8ncnn_Yolov8Ncnn_processImage(JNIEnv* env, jobject thiz, jobject bitmap)
//{
//    AndroidBitmapInfo info;
//    void* pixels = nullptr;
//
//    int ret = AndroidBitmap_getInfo(env, bitmap, &info);
//    if (ret != ANDROID_BITMAP_RESULT_SUCCESS || info.format != ANDROID_BITMAP_FORMAT_RGBA_8888)
//        return JNI_FALSE;
//
//    ret = AndroidBitmap_lockPixels(env, bitmap, &pixels);
//    if (ret != ANDROID_BITMAP_RESULT_SUCCESS)
//        return JNI_FALSE;
//
//    cv::Mat rgb(info.height, info.width, CV_8UC4, pixels);
//
//    {
//        ncnn::MutexLockGuard g(lock);
//        if (g_yolo)
//        {
//            std::vector<Object> objects;
//            g_yolo->detect(rgb, objects);
//            g_yolo->draw(rgb, objects);
//        }
//        else
//        {
//            draw_unsupported(rgb);
//        }
//    }
//
//    draw_fps(rgb);
//
//    {
//        ncnn::MutexLockGuard g(matLock);
//        if (!rgb.empty())
//        {
//            rgb.copyTo(processedMat);
//        }
//        else
//        {
//            __android_log_print(ANDROID_LOG_ERROR, "ncnn", "rgb is empty");
//            AndroidBitmap_unlockPixels(env, bitmap);
//            return JNI_FALSE;
//        }
//    }
//
//    AndroidBitmap_unlockPixels(env, bitmap);
//    return JNI_TRUE;
//}

// 保存检测结果的辅助函数
void saveDetectionResults(const cv::Mat& rgb, const std::vector<Object>& objects, const std::string& originalFilename)
{
    __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "开始保存检测到 %zu 个对象", objects.size());
    if (globalSavePath.empty()) {
        __android_log_print(ANDROID_LOG_WARN, "ncnn", "保存路径未设置，跳过保存");
        return;
    }

    // 生成唯一文件名
    static int imageCount = 0;

    // 生成新文件名
    std::string newFilename = "detect_" + originalFilename + ".jpg";;
    std::string imagePath = globalSavePath + "/" + newFilename;

    // 保存图像
    cv::Mat rgbForSave = rgb.clone();
    // 转换为BGR格式保存（OpenCV默认保存为BGR）
    if (rgbForSave.type() == CV_8UC4) {
        cv::Mat rgbBGR;
        cvtColor(rgbForSave, rgbBGR, cv::COLOR_RGBA2BGR);
        cv::imwrite(imagePath, rgbBGR);
    } else {
        cv::imwrite(imagePath, rgbForSave);
    }

    __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "图像已保存: %s", imagePath.c_str());


    std::string txtFilename = "result_" + originalFilename + ".txt";
    std::string txtPath = globalSavePath + "/" + txtFilename;

    std::ofstream txtFile(txtPath);
    if (txtFile.is_open()) {
        __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "文件是打开状态，开始保存具体信息");

        txtFile << "检测结果 - " << imagePath << std::endl;
        txtFile << "------------------------" << std::endl;

        for (const auto& obj : objects) {
            txtFile << "类别: " << (obj.label) << std::endl;
            txtFile << "置信度: " << obj.prob << std::endl;
            txtFile << "位置: x=" << obj.rect.x << ", y=" << obj.rect.y << std::endl;
            txtFile << "尺寸: width=" << obj.rect.width << ", height=" << obj.rect.height << std::endl;
            txtFile << "------------------------" << std::endl;
        }

        txtFile.close();
        __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "检测结果已保存: %s", txtPath.c_str());
    } else {
        __android_log_print(ANDROID_LOG_ERROR, "ncnn", "无法创建文本文件: %s", txtPath.c_str());
    }
}

JNIEXPORT jboolean JNICALL Java_com_tencent_yolov8ncnn_Yolov8Ncnn_processImage(JNIEnv* env, jobject thiz, jobject bitmap, jstring imageName, jobject assetManager)
{
    AndroidBitmapInfo info;
    void* pixels = nullptr;

    int ret = AndroidBitmap_getInfo(env, bitmap, &info);
    if (ret != ANDROID_BITMAP_RESULT_SUCCESS || info.format != ANDROID_BITMAP_FORMAT_RGBA_8888)
        return JNI_FALSE;

    ret = AndroidBitmap_lockPixels(env, bitmap, &pixels);
    if (ret != ANDROID_BITMAP_RESULT_SUCCESS)
        return JNI_FALSE;

    cv::Mat rgb(info.height, info.width, CV_8UC4, pixels);

    __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "开始处理图片帧！尺寸: %d x %d", rgb.cols, rgb.rows);

    // 如果是RGBA，转换为RGB
    cv::Mat inputImage;
    if (rgb.channels() == 4) {
        cv::cvtColor(rgb, inputImage, cv::COLOR_RGBA2RGB);
        __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "已将RGBA转换为RGB");
    } else {
        inputImage = rgb.clone();
    }


    // 调整图片尺寸以匹配模型输入要求
//    int modelInputSize = 640; // 根据模型设置
//    if (inputImage.cols != modelInputSize || inputImage.rows != modelInputSize) {
//
//        cv::resize(inputImage, inputImage, cv::Size(modelInputSize, modelInputSize));
//        __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "已调整图片尺寸至: %d x %d", modelInputSize, modelInputSize);
//    }
//
//    __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "开始处理图片帧！最终尺寸: %d x %d", inputImage.cols, inputImage.rows);



    std::vector<Object> objects; // 存储检测结果
    {
        ncnn::MutexLockGuard g(lock);
        if (g_yolo)
        {

            __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "g_yolo有值，开始检测！");
            g_yolo->detect(inputImage, objects);

            // 检查检测结果
            __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "检测到 %zu 个对象", objects.size());
            for (const auto& obj : objects) {
                __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "对象 - 类别: %d, 置信度: %.2f, 位置: (%d, %d), 尺寸: %d x %d",
                                    obj.label, obj.prob, obj.rect.x, obj.rect.y, obj.rect.width, obj.rect.height);
            }

            rgb = inputImage;
            g_yolo->draw(rgb, objects);
        }
        else
        {
            draw_unsupported(rgb);
        }
    }

    draw_fps(rgb);
    __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "检测到 %zu 个对象", objects.size());

    {
        ncnn::MutexLockGuard g(matLock);
        if (!rgb.empty())
        {
            rgb.copyTo(processedMat);
        }
        else
        {
            __android_log_print(ANDROID_LOG_ERROR, "ncnn", "rgb is empty");
            AndroidBitmap_unlockPixels(env, bitmap);
            return JNI_FALSE;
        }
    }
    // 保存处理后的图像和检测结果
    // 获取图片名称
    const char* imgName = env->GetStringUTFChars(imageName, nullptr);
    std::string imageNameStr(imgName);

    saveDetectionResults(rgb, objects, imageNameStr);


    AndroidBitmap_unlockPixels(env, bitmap);


    env->ReleaseStringUTFChars(imageName, imgName);

    // 获取AAssetManager
    AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);
    // 从标签文件读取真实类别
    std::vector<std::string> groundTruths = readGroundTruth(imageNameStr, mgr);

    saveToExcel(imageNameStr, objects, groundTruths);

    return JNI_TRUE;
}



//// 获取处理后的图片
//JNIEXPORT jobject JNICALL Java_com_tencent_yolov8ncnn_Yolov8Ncnn_getProcessedImage(JNIEnv* env, jobject thiz)
//{
//    ncnn::MutexLockGuard g(matLock);
//    if (processedMat.empty())
//        return nullptr;
//
//    // 获取 Bitmap 类和相关方法/字段 ID
//    jclass bitmapClass = env->FindClass("android/graphics/Bitmap");
//    jmethodID createBitmapMethod = env->GetStaticMethodID(
//            bitmapClass, "createBitmap",
//            "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
//
//    jclass bitmapConfigClass = env->FindClass("android/graphics/Bitmap$Config");
//    jfieldID argb8888Field = env->GetStaticFieldID(
//            bitmapConfigClass, "ARGB_8888", "Landroid/graphics/Bitmap$Config;");
//
//    jobject argb8888Config = env->GetStaticObjectField(bitmapConfigClass, argb8888Field);
//
//    // 创建 Bitmap 对象
//    jobject bitmap = env->CallStaticObjectMethod(
//            bitmapClass, createBitmapMethod,
//            processedMat.cols, processedMat.rows, argb8888Config);
//
//    // 将处理后的图像数据复制到 Bitmap
//    void* pixels = nullptr;
//    AndroidBitmap_lockPixels(env, bitmap, &pixels);
//    cv::Mat temp(processedMat.rows, processedMat.cols, CV_8UC4, pixels);
//    processedMat.copyTo(temp);
//    AndroidBitmap_unlockPixels(env, bitmap);
//
//    // 释放局部引用
//    env->DeleteLocalRef(bitmapClass);
//    env->DeleteLocalRef(bitmapConfigClass);
//    env->DeleteLocalRef(argb8888Config);
//
//    return bitmap;
//}


// 添加获取检测结果的方法
//JNIEXPORT jobject JNICALL Java_com_tencent_yolov8ncnn_Yolov8Ncnn_getDetectionResults(JNIEnv* env, jobject thiz)
//{
//    ncnn::MutexLockGuard g(lock);
//
//    if (!g_yolo) {
//        return nullptr;
//    }
//
//    // 获取检测结果
//    std::vector<Object> objects = g_yolo->getLatestDetections();
//
//    // 获取绘制后的图像
//    cv::Mat drawn_image = g_yolo->getDrawnImage();
//
//
//    // 创建Java端的DetectionResult列表
//    jclass listClass = env->FindClass("java/util/ArrayList");
//    jmethodID listConstructor = env->GetMethodID(listClass, "<init>", "()V");
//    jmethodID listAdd = env->GetMethodID(listClass, "add", "(Ljava/lang/Object;)Z");
//    jobject resultList = env->NewObject(listClass, listConstructor);
//
//    jclass resultClass = env->FindClass("com/tencent/yolov8ncnn/DetectionResult");
//    jmethodID resultConstructor = env->GetMethodID(
//            resultClass, "<init>",
//            "(Ljava/lang/String;FFFFF)V");
//    for (const Object& obj : objects) {
//        jobject jresult = env->NewObject(resultClass, resultConstructor,
//                                         obj.label,
//                                         obj.prob,
//                                         obj.rect.x, obj.rect.y,
//                                         obj.rect.width, obj.rect.height);
//        env->CallBooleanMethod(resultList, listAdd, jresult);
//        env->DeleteLocalRef(jresult);
//    }
//
//    // 将OpenCV Mat转换为Android Bitmap
//    jclass bitmapClass = env->FindClass("android/graphics/Bitmap");
//    jmethodID createBitmapMethod = env->GetStaticMethodID(
//            bitmapClass, "createBitmap",
//            "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
//
//    jclass bitmapConfigClass = env->FindClass("android/graphics/Bitmap$Config");
//    jfieldID argb8888Field = env->GetStaticFieldID(
//            bitmapConfigClass, "ARGB_8888", "Landroid/graphics/Bitmap$Config;");
//    jobject argb8888Config = env->GetStaticObjectField(bitmapConfigClass, argb8888Field);
//
//    jobject bitmap = env->CallStaticObjectMethod(
//            bitmapClass, createBitmapMethod,
//            drawn_image.cols, drawn_image.rows, argb8888Config);
//
//    // 将图像数据复制到Bitmap
//    void* pixels = nullptr;
//    AndroidBitmap_lockPixels(env, bitmap, &pixels);
//    cv::Mat temp(drawn_image.rows, drawn_image.cols, CV_8UC4, pixels);
//    cvtColor(drawn_image, temp, cv::COLOR_BGR2RGBA); // OpenCV使用BGR，Android需要RGBA
//    AndroidBitmap_unlockPixels(env, bitmap);
//
//    // 创建包含结果和Bitmap的Java对象
//    jclass detectionResultClass = env->FindClass("com/tencent/yolov8ncnn/DetectionResultWrapper");
//    jmethodID detectionResultConstructor = env->GetMethodID(
//            detectionResultClass, "<init>",
//            "(Ljava/util/List;Landroid/graphics/Bitmap;)V");
//
//    jobject resultWrapper = env->NewObject(
//            detectionResultClass, detectionResultConstructor,
//            resultList, bitmap);
//
//    // 清理本地引用
//    env->DeleteLocalRef(bitmapClass);
//    env->DeleteLocalRef(bitmapConfigClass);
//    env->DeleteLocalRef(argb8888Config);
//
//    return resultWrapper;
//
//}

JNIEXPORT void JNICALL Java_com_tencent_yolov8ncnn_Yolov8Ncnn_setSavePath(JNIEnv* env, jobject thiz, jstring path)
{
    if (path) {
        const char* savePath = env->GetStringUTFChars(path, nullptr);
        globalSavePath = savePath;
        env->ReleaseStringUTFChars(path, savePath);
        __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "保存路径已设置: %s", globalSavePath.c_str());
    } else {
        __android_log_print(ANDROID_LOG_WARN, "ncnn", "保存路径为空");
        globalSavePath.clear();
    }
}
// 辅助函数：清理本地引用
void cleanupReferences(JNIEnv* env, ...) {
    va_list args;
    va_start(args, env);

    jobject ref;
    while ((ref = va_arg(args, jobject)) != nullptr) {
        env->DeleteLocalRef(ref);
    }

    va_end(args);
}
//JNIEXPORT jobject JNICALL Java_com_tencent_yolov8ncnn_Yolov8Ncnn_getDetectionResults(JNIEnv* env, jobject thiz)
//{
//    ncnn::MutexLockGuard g(lock);
//    __android_log_print(ANDROID_LOG_ERROR, "ncnn", "进入获取cppJava_com_tencent_yolov8ncnn_Yolov8Ncnn_getDetectionResults");
//
//    // 检查g_yolo是否有效
//    if (!g_yolo) {
//        __android_log_print(ANDROID_LOG_ERROR, "ncnn", "g_yolo is null");
//        return nullptr;
//    }
//
//    // 获取检测结果
//    std::vector<Object> objects = g_yolo->getLatestDetections();
//
//    // 获取绘制后的图像
//    cv::Mat drawn_image = g_yolo->getDrawnImage();
//
//    // 检查图像是否有效
//    if (drawn_image.empty()) {
//        __android_log_print(ANDROID_LOG_ERROR, "ncnn", "drawn_image is empty");
//        return nullptr;
//    }
//
//    // 创建Java端的DetectionResult列表
//    jclass listClass = env->FindClass("java/util/ArrayList");
//    if (!listClass) {
//        __android_log_print(ANDROID_LOG_ERROR, "ncnn", "Failed to find ArrayList class");
//        return nullptr;
//    }
//
//    jmethodID listConstructor = env->GetMethodID(listClass, "<init>", "()V");
//    if (!listConstructor) {
//        __android_log_print(ANDROID_LOG_ERROR, "ncnn", "Failed to find ArrayList constructor");
//        env->DeleteLocalRef(listClass);
//        return nullptr;
//    }
//
//    jmethodID listAdd = env->GetMethodID(listClass, "add", "(Ljava/lang/Object;)Z");
//    if (!listAdd) {
//        __android_log_print(ANDROID_LOG_ERROR, "ncnn", "Failed to find ArrayList add method");
//        env->DeleteLocalRef(listClass);
//        return nullptr;
//    }
//
//    jobject resultList = env->NewObject(listClass, listConstructor);
//    if (!resultList) {
//        __android_log_print(ANDROID_LOG_ERROR, "ncnn", "Failed to create ArrayList instance");
//        env->DeleteLocalRef(listClass);
//        return nullptr;
//    }
//
//    jclass resultClass = env->FindClass("com/tencent/yolov8ncnn/DetectionResult");
//    if (!resultClass) {
//        __android_log_print(ANDROID_LOG_ERROR, "ncnn", "Failed to find DetectionResult class");
//        env->DeleteLocalRef(listClass);
//        env->DeleteLocalRef(resultList);
//        return nullptr;
//    }
//
//    jmethodID resultConstructor = env->GetMethodID(
//            resultClass, "<init>",
//            "(Ljava/lang/String;FFFFF)V");
//    if (!resultConstructor) {
//        __android_log_print(ANDROID_LOG_ERROR, "ncnn", "Failed to find DetectionResult constructor");
//        env->DeleteLocalRef(listClass);
//        env->DeleteLocalRef(resultList);
//        env->DeleteLocalRef(resultClass);
//        return nullptr;
//    }
//
//    // 处理检测结果对象
//    for (const Object& obj : objects) {
//        // 确保obj.label有效
//        const char* labelChars = obj.label ? reinterpret_cast<const char *>(obj.label) : "";
//        jstring jlabel = env->NewStringUTF(labelChars);
//
//        jobject jresult = env->NewObject(resultClass, resultConstructor,
//                                         jlabel,
//                                         obj.prob,
//                                         obj.rect.x, obj.rect.y,
//                                         obj.rect.width, obj.rect.height);
//        if (!jresult) {
//            __android_log_print(ANDROID_LOG_ERROR, "ncnn", "Failed to create DetectionResult instance");
//            env->DeleteLocalRef(jlabel);
//            continue;
//        }
//
//        jboolean addResult = env->CallBooleanMethod(resultList, listAdd, jresult);
//        if (!addResult) {
//            __android_log_print(ANDROID_LOG_ERROR, "ncnn", "Failed to add to resultList");
//        }
//
//        env->DeleteLocalRef(jresult);
//        env->DeleteLocalRef(jlabel);
//    }
//
//    // 将OpenCV Mat转换为Android Bitmap
//    jclass bitmapClass = env->FindClass("android/graphics/Bitmap");
//    if (!bitmapClass) {
//        __android_log_print(ANDROID_LOG_ERROR, "ncnn", "Failed to find Bitmap class");
//        // 清理已创建的引用
//        cleanupReferences(env, listClass, resultList, resultClass);
//        return nullptr;
//    }
//
//    jmethodID createBitmapMethod = env->GetStaticMethodID(
//            bitmapClass, "createBitmap",
//            "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
//    if (!createBitmapMethod) {
//        __android_log_print(ANDROID_LOG_ERROR, "ncnn", "Failed to find createBitmap method");
//        cleanupReferences(env, listClass, resultList, resultClass, bitmapClass);
//        return nullptr;
//    }
//
//    jclass bitmapConfigClass = env->FindClass("android/graphics/Bitmap$Config");
//    if (!bitmapConfigClass) {
//        __android_log_print(ANDROID_LOG_ERROR, "ncnn", "Failed to find Bitmap$Config class");
//        cleanupReferences(env, listClass, resultList, resultClass, bitmapClass);
//        return nullptr;
//    }
//
//    jfieldID argb8888Field = env->GetStaticFieldID(
//            bitmapConfigClass, "ARGB_8888", "Landroid/graphics/Bitmap$Config;");
//    if (!argb8888Field) {
//        __android_log_print(ANDROID_LOG_ERROR, "ncnn", "Failed to find ARGB_8888 field");
//        cleanupReferences(env, listClass, resultList, resultClass, bitmapClass, bitmapConfigClass);
//        return nullptr;
//    }
//
//    jobject argb8888Config = env->GetStaticObjectField(bitmapConfigClass, argb8888Field);
//    if (!argb8888Config) {
//        __android_log_print(ANDROID_LOG_ERROR, "ncnn", "Failed to get ARGB_8888 config");
//        cleanupReferences(env, listClass, resultList, resultClass, bitmapClass, bitmapConfigClass);
//        return nullptr;
//    }
//
//    jobject bitmap = env->CallStaticObjectMethod(
//            bitmapClass, createBitmapMethod,
//            drawn_image.cols, drawn_image.rows, argb8888Config);
//    if (!bitmap) {
//        __android_log_print(ANDROID_LOG_ERROR, "ncnn", "Failed to create Bitmap");
//        cleanupReferences(env, listClass, resultList, resultClass, bitmapClass, bitmapConfigClass, argb8888Config);
//        return nullptr;
//    }
//
//    // 将图像数据复制到Bitmap
//    void* pixels = nullptr;
//    int ret = AndroidBitmap_lockPixels(env, bitmap, &pixels);
//    if (ret != ANDROID_BITMAP_RESULT_SUCCESS) {
//        __android_log_print(ANDROID_LOG_ERROR, "ncnn", "Failed to lock Bitmap pixels");
//        cleanupReferences(env, listClass, resultList, resultClass, bitmapClass, bitmapConfigClass, argb8888Config, bitmap);
//        return nullptr;
//    }
//
//
//    cv::Mat temp(drawn_image.rows, drawn_image.cols, CV_8UC4, pixels);
//    cvtColor(drawn_image, temp, cv::COLOR_BGR2RGBA); // OpenCV使用BGR，Android需要RGBA
//
//
//    AndroidBitmap_unlockPixels(env, bitmap);
//
//    // 创建包含结果和Bitmap的Java对象
//    jclass detectionResultClass = env->FindClass("com/tencent/yolov8ncnn/DetectionResultWrapper");
//    if (!detectionResultClass) {
//        __android_log_print(ANDROID_LOG_ERROR, "ncnn", "Failed to find DetectionResultWrapper class");
//        cleanupReferences(env, listClass, resultList, resultClass, bitmapClass, bitmapConfigClass, argb8888Config, bitmap);
//        return nullptr;
//    }
//
//    jmethodID detectionResultConstructor = env->GetMethodID(
//            detectionResultClass, "<init>",
//            "(Ljava/util/List;Landroid/graphics/Bitmap;)V");
//    if (!detectionResultConstructor) {
//        __android_log_print(ANDROID_LOG_ERROR, "ncnn", "Failed to find DetectionResultWrapper constructor");
//        cleanupReferences(env, listClass, resultList, resultClass, bitmapClass, bitmapConfigClass, argb8888Config, bitmap, detectionResultClass);
//        return nullptr;
//    }
//
//    jobject resultWrapper = env->NewObject(
//            detectionResultClass, detectionResultConstructor,
//            resultList, bitmap);
//    if (!resultWrapper) {
//        __android_log_print(ANDROID_LOG_ERROR, "ncnn", "Failed to create DetectionResultWrapper instance");
//        cleanupReferences(env, listClass, resultList, resultClass, bitmapClass, bitmapConfigClass, argb8888Config, bitmap, detectionResultClass);
//        return nullptr;
//    }
//
//    // 清理本地引用
//    cleanupReferences(env, listClass, resultList, resultClass, bitmapClass, bitmapConfigClass, argb8888Config, bitmap, detectionResultClass);
//
//    return resultWrapper;
//}





}
